home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-02-26 | 13.2 KB | 413 lines | [TEXT/CWIE] |
- #include <Devices.h>
- #include <Fonts.h>
- #include <ImageCompression.h>
- #include <Movies.h>
-
- Boolean gDecompressingSourceFrame;
- Boolean gCompressingSourceFrame;
- Boolean gDecompressingToScreen;
-
- pascal void decompressSrcFrameDone(OSErr result, short flags, long refcon);
- pascal void compressSrcFrameDone(OSErr result, short flags, long refcon);
- pascal void decompressToScreenDone(OSErr result, short flags, long refcon);
-
- #define MAX_SAMPLES 60
-
- typedef struct {
- long duration; // in milliseconds
- long size; // sample size in bytes
- } SampleRecord;
-
- typedef struct {
- long duration;
- long fileOffset;
- long dataSize;
- Boolean isKeyFrame;
- char pad[3];
- } SampleEntryRecord, **SampleEntry;
-
- void main(void)
- {
- OSErr err;
- StandardFileReply reply;
- SFTypeList types;
- Movie m;
- short resFref;
- WindowPtr w;
- Rect bounds;
- Track srcVideoTrack = nil;
- Media srcVideoMedia;
- Track dstVideoTrack = nil;
- GWorldPtr gw[3];
- ImageDescriptionHandle srcDesc = nil;
- ImageSequence srcDecoSequences[3];
- TimeValue timeNow;
- TimeValue srcMovieDuration;
- Handle srcVideoData1 = NewHandle(0);
- Handle srcVideoData2 = NewHandle(0);
- CodecFlags outFlags;
- long srcVideoDataSize1, srcVideoDataSize2;
- TimeValue mediaTimeNow;
- Boolean useFirstBufferForCompress;
- ICMCompletionProcRecord srcDecoCompletion, compressCompletion, screenDecoCompletion;
- ImageDescriptionHandle compressedDesc = nil;
- ImageSequence compSequence = 0;
- long maxCompressionBufferSize;
- Handle compressedData1 = nil, compressedData2 = nil;
- long compressedDataSize1 = 0, compressedDataSize2 = 0;
- UInt8 compressedSimilarity1, compressedSimilarity2;
- ImageSequence screenDecoSequence = 0;
- long i;
- long currentCompressGWorldIndex;
- long currentDecompressGWorldIndex;
- DataRateParams dataRateStuff;
- long sampleCount = 0;
- SampleRecord sampleRecords[MAX_SAMPLES];
- long totalDuration = 0, totalSize = 0;
- SampleEntry theSampleRefs = (SampleEntry)NewHandle(0);
- long currentFileOffset = 0;
- short outputFref = 0;
- IOParam writeBlock;
- short outputResRef = -1;
- Movie newMovie = nil;
-
- Handle compressedFrameDurations = NewHandle(0);
- Handle compressedFrameSize = NewHandle(0);
-
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(0L);
- InitCursor();
- MaxApplZone();
-
- EnterMovies();
-
- types[0] = MovieFileType;
- StandardGetFilePreview(nil, 1, types, &reply);
- if (!reply.sfGood) return;
-
- SetRect(&bounds, 75, 75, 75+160,75+120);
- w = NewCWindow(nil, &bounds, reply.sfFile.name, false, 0, (WindowPtr)-1,
- true, 0);
- if (!w) return;
-
- SetPort(w);
-
- err = OpenMovieFile(&reply.sfFile, &resFref, fsRdPerm);
- if (err) return;
-
- err = NewMovieFromFile(&m, resFref, nil, (StringPtr)nil,
- newMovieActive, nil);
- if (err) return;
-
- CloseMovieFile(resFref);
-
- // create the output file
- reply.sfFile.name[++reply.sfFile.name[0]] = '!';
- err = CreateMovieFile(&reply.sfFile, 'TVOD', reply.sfScript, createMovieFileDeleteCurFile, &outputResRef, &newMovie);
- if (err) return;
-
- err = FSpOpenDF(&reply.sfFile, fsRdWrPerm, &outputFref);
- if (err) return;
-
- writeBlock.ioResult = 0;
-
- GetMovieBox(m, &bounds);
- OffsetRect(&bounds, -bounds.left, -bounds.top);
- SetMovieBox(m, &bounds);
-
- SizeWindow(w, bounds.right, bounds.bottom, false);
- ShowWindow(w);
-
- for (i=0; i<3; i++) {
- err = NewGWorld(&gw[i], 32, &bounds, nil, nil, 0);
- if (err) {
- err = NewGWorld(&gw[i], 32, &bounds, nil, nil, useTempMem);
- if (err) return;
- }
- LockPixels(gw[i]->portPixMap);
- }
-
- srcVideoTrack = GetMovieIndTrackType(m, 1, 'vide', movieTrackEnabledOnly | movieTrackMediaType);
- if (!srcVideoTrack) return;
-
- srcVideoMedia = GetTrackMedia(srcVideoTrack);
- srcDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
- if (!srcDesc) return;
- GetMediaSampleDescription(srcVideoMedia, 1, (SampleDescriptionHandle)srcDesc);
-
- for (i=0; i<3; i++) {
- err = DecompressSequenceBegin(&srcDecoSequences[i], srcDesc, gw[i], nil, nil, nil, ditherCopy, nil, 0, codecNormalQuality, anyCodec);
- if (err) return;
- }
-
- srcDecoCompletion.completionProc = NewICMCompletionProc(decompressSrcFrameDone);
- srcDecoCompletion.completionRefCon = (long)&gDecompressingSourceFrame;
- gDecompressingSourceFrame = false;
-
- compressCompletion.completionProc = NewICMCompletionProc(compressSrcFrameDone);
- compressCompletion.completionRefCon = (long)&gCompressingSourceFrame;
- gCompressingSourceFrame = false;
-
- screenDecoCompletion.completionProc = NewICMCompletionProc(decompressToScreenDone);
- screenDecoCompletion.completionRefCon = (long)&gDecompressingToScreen;
- gDecompressingToScreen = false;
-
- compressedDesc = (ImageDescriptionHandle)NewHandle(0);
- if (!compressedDesc) return;
-
- err = CompressSequenceBegin(&compSequence, gw[0]->portPixMap, nil, nil, nil, 24, 'cvid', anyCodec, codecLosslessQuality - 1, codecLosslessQuality - 1, 15, nil, nil, compressedDesc);
- if (err) return;
-
- err = GetMaxCompressionSize(gw[0]->portPixMap, &gw[0]->portRect, 24, codecLosslessQuality - 1, 'cvid', anyCodec, &maxCompressionBufferSize);
- if (err) return;
-
- compressedData1 = NewHandle(maxCompressionBufferSize);
- compressedData2 = NewHandle(maxCompressionBufferSize);
- if (!compressedData1 || !compressedData2)
- return;
-
- HLockHi(compressedData1);
- HLockHi(compressedData2);
-
- dataRateStuff.dataRate = 240 * 1024;
- dataRateStuff.keyFrameRate = 30;
- dataRateStuff.minSpatialQuality = codecLosslessQuality - 1;
- dataRateStuff.minTemporalQuality = codecLosslessQuality - 1;
- totalDuration = 1000;
- totalSize = dataRateStuff.dataRate;
- sampleRecords[0].size = dataRateStuff.dataRate;
- sampleRecords[0].duration = 1000;
- sampleCount = 1;
-
- srcMovieDuration = GetMovieDuration(m);
- timeNow = 0;
-
- // prime the loop by decompressing the first frame into the first gworld
- mediaTimeNow = TrackTimeToMediaTime(timeNow, srcVideoTrack);
- if (mediaTimeNow == -1) return;
-
- err = GetMediaSample(srcVideoMedia, srcVideoData1, 0, &srcVideoDataSize1, mediaTimeNow, nil, nil, nil, nil, 1, nil, nil);
- if (err) return;
-
- HLock(srcVideoData1);
- err = DecompressSequenceFrameS(srcDecoSequences[0], *srcVideoData1, srcVideoDataSize1, 0, &outFlags, nil);
- if (err) return;
-
- HUnlock(srcVideoData1);
-
- // figure out the next frame time
- GetTrackNextInterestingTime(srcVideoTrack, nextTimeMediaSample | nextTimeIgnoreActiveSegment, timeNow, 1, &timeNow, nil);
- if (timeNow == -1) return;
-
- // load the next frame to decompress
- mediaTimeNow = TrackTimeToMediaTime(timeNow, srcVideoTrack);
- if (mediaTimeNow == -1) return;
-
- err = GetMediaSample(srcVideoMedia, srcVideoData1, 0, &srcVideoDataSize1, mediaTimeNow, nil, nil, nil, nil, 1, nil, nil);
- if (err) return;
-
- // initialize more stuff
- useFirstBufferForCompress = true;
- currentCompressGWorldIndex = 0;
- currentDecompressGWorldIndex = 1;
-
- while (timeNow < srcMovieDuration) {
- TimeValue mediaTimeNow = TrackTimeToMediaTime(timeNow, srcVideoTrack);
-
- if (Button())
- break;
-
- if (mediaTimeNow != -1) {
- // wait for last source frame to finish decompressing
- while (gDecompressingSourceFrame)
- ;
-
- // start that next source frame decompressing
- gDecompressingSourceFrame = true;
- HLock(useFirstBufferForCompress ? srcVideoData1 : srcVideoData2);
- err = DecompressSequenceFrameS(srcDecoSequences[currentDecompressGWorldIndex],
- useFirstBufferForCompress ? *srcVideoData1 : *srcVideoData2,
- useFirstBufferForCompress ? srcVideoDataSize1 : srcVideoDataSize2, 0, &outFlags, &srcDecoCompletion);
- if (err) return;
-
- // read next source frame
- HUnlock(useFirstBufferForCompress ? srcVideoData2 : srcVideoData1);
- err = GetMediaSample(srcVideoMedia, useFirstBufferForCompress ? srcVideoData2 : srcVideoData1,
- 0, useFirstBufferForCompress ? &srcVideoDataSize2 : &srcVideoDataSize1, mediaTimeNow, nil, nil, nil, nil, 1, nil, nil);
- if (err) return;
-
- // wait for last compress to finish compressing
- while (gCompressingSourceFrame)
- ;
-
- // figure out the data rate parameters for this next frame
- if (sampleCount < MAX_SAMPLES) {
- SampleRecord *srp = &sampleRecords[sampleCount];
- srp->duration = 33; //•• evil
- srp->size = useFirstBufferForCompress ? compressedDataSize2 : compressedDataSize1;
- totalDuration += 33; //•• evil
- totalSize += srp->size;
- sampleCount++;
- }
-
- // drop (totalDuration - 1000) worth of sample data
- {
- long n = totalDuration - 1000;
- while (n && totalDuration && sampleCount) {
- if (n - sampleRecords[0].duration >= 0) {
- short i;
- n -= sampleRecords[0].duration;
- totalDuration -= sampleRecords[0].duration;
- totalSize -= sampleRecords[0].size;
- for (i = 1; i < sampleCount; i++)
- sampleRecords[i-1] = sampleRecords[i];
- sampleCount--;
- } else {
- long dec = n * sampleRecords[0].size / sampleRecords[0].duration;
- sampleRecords[0].size -= dec;
- sampleRecords[0].duration -= n;
- totalSize -= dec;
- totalDuration -= n;
- n = 0;
- }
- }
- }
-
- dataRateStuff.dataOverrun = totalSize - dataRateStuff.dataRate;
- dataRateStuff.frameDuration = 33; //•• evil
- SetCSequenceDataRateParams(compSequence, &dataRateStuff);
-
- if (screenDecoSequence) {
- // write out to disk the most recently compressed frame
- SampleEntryRecord ser;
-
- ser.duration = 33; //•• evil
- ser.fileOffset = currentFileOffset;
- ser.dataSize = useFirstBufferForCompress ? compressedDataSize2 : compressedDataSize1;
- ser.isKeyFrame = (useFirstBufferForCompress ? compressedSimilarity2 : compressedSimilarity1) == 0;
- err = PtrAndHand(&ser, (Handle)theSampleRefs, sizeof(ser));
- if (err) break;
-
- // wait for previous write to complete
- while (writeBlock.ioResult == 1)
- ;
-
- if (writeBlock.ioResult != noErr) return;
-
- writeBlock.ioRefNum = outputFref;
- writeBlock.ioPosMode = fsFromStart;
- writeBlock.ioPosOffset = currentFileOffset;
- writeBlock.ioReqCount = ser.dataSize;
- writeBlock.ioBuffer = useFirstBufferForCompress ? *compressedData2 : *compressedData1;
- writeBlock.ioCompletion = nil;
-
- PBWriteAsync((ParmBlkPtr)&writeBlock);
-
- currentFileOffset += ser.dataSize;
- }
-
- // compress last source frame
- err = SetCSequencePrev(compSequence, gw[(currentCompressGWorldIndex + 2) % 3]->portPixMap, &gw[0]->portRect);
- if (err) return;
-
- err = CompressSequenceFrame(compSequence, gw[currentCompressGWorldIndex]->portPixMap,
- nil, 0, useFirstBufferForCompress ? *compressedData1 : *compressedData2,
- useFirstBufferForCompress ? &compressedDataSize1 : &compressedDataSize2,
- useFirstBufferForCompress ? &compressedSimilarity1 : &compressedSimilarity2,
- &compressCompletion);
- if (err) return;
-
- // wait for decompress to screen frame to finish decompressing
- while (gDecompressingToScreen)
- ;
-
- // probably decompress the last compressed frame to the screen
- if (!screenDecoSequence) {
- // first time around, just make up the decompress sequence
- err = DecompressSequenceBegin(&screenDecoSequence, compressedDesc, (CGrafPtr)w, nil, nil, nil, ditherCopy, nil, 0, codecNormalQuality, anyCodec);
- if (err) return;
- }
- else {
- // all other times, decompress last compressed frame to screen
- gDecompressingToScreen = true;
- err = DecompressSequenceFrameS(screenDecoSequence,
- useFirstBufferForCompress ? *compressedData2 : *compressedData1,
- useFirstBufferForCompress ? compressedDataSize2 : compressedDataSize1, 0, &outFlags, &screenDecoCompletion);
- if (err) return;
- }
-
- useFirstBufferForCompress = !useFirstBufferForCompress;
- currentCompressGWorldIndex = (currentCompressGWorldIndex + 1) % 3;
- currentDecompressGWorldIndex = (currentDecompressGWorldIndex + 1) % 3;
- }
-
- GetTrackNextInterestingTime(srcVideoTrack, nextTimeMediaSample | nextTimeIgnoreActiveSegment, timeNow, 1, &timeNow, nil);
- if (timeNow == -1)
- timeNow = srcMovieDuration;
- }
-
- {
- long sampleCount = GetHandleSize((Handle)theSampleRefs) / sizeof(SampleEntryRecord);
- long i;
- Track dstVideoTrack;
- Media dstVideoMedia;
-
- dstVideoTrack = NewMovieTrack(newMovie, (**compressedDesc).width << 16, (**compressedDesc).height << 16, 0);
- dstVideoMedia = NewTrackMedia(dstVideoTrack, 'vide', 1000, nil, 0);
-
- for (i=0; i<sampleCount; i++) {
- SampleEntryRecord ser = (*theSampleRefs)[i];
-
- err = AddMediaSampleReference(dstVideoMedia, ser.fileOffset, ser.dataSize, ser.duration, (SampleDescriptionHandle)compressedDesc,
- 1, ser.isKeyFrame ? 0 : mediaSampleNotSync, nil);
- if (err) return;
- }
-
- err = InsertMediaIntoTrack(dstVideoTrack, 0, 0, GetMediaDuration(dstVideoMedia), 1 << 16);
- if (err) return;
-
- err = AddMovieResource(newMovie, outputResRef, nil, nil);
- if (err) return;
- }
-
- bail:
- CDSequenceEnd(screenDecoSequence);
-
- for (i=0; i<3; i++)
- CDSequenceEnd(srcDecoSequences[i]);
-
- CDSequenceEnd(compSequence);
-
- if (outputFref) FSClose(outputFref);
- if (outputResRef != -1) CloseMovieFile(outputResRef);
-
- if (newMovie) DisposeMovie(newMovie);
- }
-
- pascal void decompressSrcFrameDone(OSErr /* result */, short flags, long refcon)
- {
- Boolean *decompressingFlag = (Boolean *)refcon;
-
- if (flags & codecCompletionDest)
- *decompressingFlag = false;
- }
-
- pascal void compressSrcFrameDone(OSErr /* result */, short flags, long refcon)
- {
- Boolean *compressingFlag = (Boolean *)refcon;
-
- if (flags & codecCompletionDest)
- *compressingFlag = false;
- }
-
- pascal void decompressToScreenDone(OSErr /* result */, short flags, long refcon)
- {
- Boolean *decompressingFlag = (Boolean *)refcon;
- if (flags & codecCompletionDest)
- *decompressingFlag = false;
- }
-